package graph_viewer.structure.builder;

import java.awt.*;
import java.io.*;
import java.util.*;

import graph_viewer.util.*;
import graph_viewer.structure.*;

/**
	this class read data from the .inf file, which format is defined by Paul Wanchun Li
*/// read node data from file stream, and create a generic tree
public class Tab_Format_Graph_Builder extends Basic_Builder{

	private File	node_data;

	//============================================================================
	// constructor
	//============================================================================	
	public Tab_Format_Graph_Builder( String a_file_name ) throws IOException{
		this( new File(a_file_name) );		
	}

	public Tab_Format_Graph_Builder( File a_file ) throws IOException{
		if ( is_valid_data_file(a_file) ){
			set_file( a_file );
			//Debug.println( " File is NOT null " , 2);
		} else {
			Debug.println( " File is null " , 2);
			node_data	= null;
		}
	}

	//============================================================================
	// setter&getter
	//============================================================================
	public void set_file( File a_file ){
		node_data	= a_file;
	}

	public File get_file(){
		return this.node_data;
	}
	//============================================================================
	// public methods
	//============================================================================
	public Graph build_clustered_graph( Tree cluster_tree ) throws IOException {
		Tree created_cluster_tree	 = build_tree( cluster_tree );

		Clustered_Graph	a_c_g	= new Clustered_Graph( created_cluster_tree );
		ArrayList				edges		= build_edges( a_c_g );
		a_c_g.set_edges( edges );

		return a_c_g;
	}
	
	
	//the first element of collection must be the node
	public Tree build_tree( Tree created_tree ) throws IOException{
		ArrayList	node_information_list	= create_node_information_list();
		
		Debug.println("====================build_tree==================================", 2 );
		for ( Iterator iter = node_information_list.iterator() ; iter.hasNext() ; ){
			ArrayList an_element_node_information_list	= (ArrayList)iter.next();			
			Node	an_node	 = create_tree_node( an_element_node_information_list );
			created_tree.add_node(an_node);
		}
		
		//create clustered node	//
		ArrayList clustered_node_list	= get_clustered_node(  );
		
		for ( Iterator _i = clustered_node_list.iterator(); _i.hasNext() ; ){
			String a_clustered_node_line	= (String)_i.next();
			String label		= retrive_clustered_node_information( a_clustered_node_line );
			Node clustered_node	 = created_tree.search( label );
			clustered_node.set_is_closed( true );
		}
		
		//Debug.println("================================================================", 2);
		Out.println( clustered_node_list.size() + " clustered nodes." );
		/**/
		Debug.println("===================build_tree end==================================", 2);
		
		return created_tree;
	}

	public ArrayList build_edges( Graph a_graph ) throws IOException{
		ArrayList edges_info = read_edges( node_data );
		ArrayList edges		= new ArrayList();

		for ( Iterator iter=edges_info.iterator(); iter.hasNext(); ){
			String one_edge_info	= (String)iter.next();
			String[] end_points		= retrive_edge_information( one_edge_info, 1 );
			//Edge an_edge			= create_one_edge( a_graph, end_points );
			edges.add( end_points );
		}		

		return edges;
	}



	//============================================================================
	// private methods
	//============================================================================
	protected String[] retrive_edge_information( String cross_vertice_pair, int start_index ){
		ArrayList edge_info = new ArrayList();
		StringTokenizer st	= new StringTokenizer( cross_vertice_pair );
		while ( st.hasMoreTokens() ){
			String s	= st.nextToken();
			//Debug.println( "parse edge info " + s, 2 );
			edge_info.add( s );
		}
		
		String 
			start_node	= (String)edge_info.get( start_index ),
			end_node	= (String)edge_info.get( start_index  + 1 );

		return new String[]{ start_node, end_node };
	}

	private ArrayList get_clustered_node( ) throws IOException{
		BufferedReader	node_data_reader	= new BufferedReader( new InputStreamReader( new FileInputStream( this.node_data ) ) );

		ArrayList		node_list			= new ArrayList();

		while ( true ){
			String node_list_string = node_data_reader.readLine().trim() ;

			if ( is_closed_node_start( node_list_string ) ){
				node_list.add( node_list_string );
			}else if( is_end_flag( node_list_string ) ) {
				break;
			} else {
				continue;
			} 

		}

		node_data_reader.close();

		return node_list;
	}
	

	private ArrayList read_edges( File a_file ) throws IOException{
		BufferedReader	node_data_reader	= new BufferedReader( new InputStreamReader( new FileInputStream( this.node_data ) ) );

		ArrayList		edges_info				= new ArrayList();

		while ( true ){
			String node_list_string = node_data_reader.readLine().trim() ;
			if ( is_closed_graph_edge_start( node_list_string ) ){
				edges_info.add( node_list_string );	
			}else if ( is_end_flag( node_list_string ) ){
				break;
			}else{
				continue;
			}			
		}

		node_data_reader.close();

		return edges_info;
	}

	//@param element are arraylists that contains node, parent, sibling labels
	private Node create_tree_node( ArrayList node_information_list){
		String 
			node_label	= (String)node_information_list.get(0),
			parent_label	=  (String)node_information_list.get(1),
			sibling_label	= (String)node_information_list.get(2);

		String
			x_center		= (String)node_information_list.get(3),
			y_center		= (String)node_information_list.get(4);
		
		Node	new_node;

		if ( Structure_Util.is_null_label(parent_label) ){
			new_node	 = new Node( node_label );
		}else{
			new_node	 = new Node( node_label, new Node( parent_label ) );
		}

		Point location	= new Point( (int)Double.parseDouble( x_center ), (int)Double.parseDouble( y_center ) );

		int
			default_width	= Structure_Util.find_default_node_width(),
			default_height	= Structure_Util.find_default_node_height();

		Node_Position np=  new Node_Position
						(	Integer.parseInt( x_center ),
							Integer.parseInt( y_center ),
							default_width,
							default_height
						);
		new_node.set_position( np );
//		new_node.set_normal_position( np );
//		new_node.set_distorted_position( np );
			
//		//Debug.println( "creat a new node "+ new_node + ", postion is: " + new_node.get_position() );

		return new_node;
	}
	
	//@return  element are arraylists that contains node, parent, sibling labels.
	private ArrayList create_node_information_list() throws IOException{
		ArrayList node_information_list	= new ArrayList();

		ArrayList node_string_list	= read_nodes( this.node_data ); 

		for ( Iterator iter = node_string_list.iterator() ; iter.hasNext() ; ){
			node_information_list.add( retrive_node_information( (String)iter.next() ) );
		}
		
		return node_information_list;	
	}


	private ArrayList read_nodes( File a_file ) throws IOException{
		BufferedReader	node_data_reader	= new BufferedReader( new InputStreamReader( new FileInputStream( this.node_data ) ) );

		ArrayList		node_list			= new ArrayList();

		while ( true ){
			String node_list_string = node_data_reader.readLine().trim() ;
			
			if ( is_node_start( node_list_string ) ){
				node_list.add( node_list_string );
			}else if( is_end_flag( node_list_string ) ){
				break;
			}else{
				continue;
			}
		}

		node_data_reader.close();

		return node_list;
	}

	// @return the arraylist incudling: node label ,child, sibling, and parent label.
	private ArrayList retrive_node_information( String node_string ){
		ArrayList	node_list		= new ArrayList();
		StringTokenizer st	= new StringTokenizer( node_string );
		while ( st.hasMoreTokens() ){
			node_list.add( st.nextToken() );
		}

		return node_list;
	}

	private Edge create_one_edge( Graph a_graph, String[] end_points ){
		Node start_node	= a_graph.search( end_points[0] );
		Node end_node	= a_graph.search( end_points[1] );

		return new Edge( start_node, end_node );
	}

	private String retrive_clustered_node_information( String clustered_node_information ){
		return clustered_node_information.substring( 1, clustered_node_information.length() ).trim();
	}


};
